<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Simulated OS 10 TV For Production Environment - Discovery Search</title>
    <link href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/5.1.3/css/bootstrap.min.css" rel="stylesheet">
    <style>
        body, html { background: #111 !important; overflow-x: hidden; }
        .top-bar { position: fixed; top: 0; left: 0; width: 100%; background: #222; z-index: 1000; border-bottom: 1px solid #eee; padding: 10px 0; }
        .top-bar .btn { margin-right: 8px; }
        .top-bar .fw-bold { color: #fff; }
        .sidebar { width: 200px; min-width: 200px; max-width: 200px; flex-shrink: 0; background: #222; height: calc(100vh - 56px); top: 56px; padding-top: 0; border-right: 1px solid #eee; position: fixed; left: 0; z-index: 1050; white-space: nowrap; }
        .sidebar .nav-link { color: #fff; font-size: 1.1em; margin-bottom: 8px; border-radius: 8px; transition: background 0.2s, color 0.2s; display: inline-block; float: none; }
        .sidebar .nav-link.active { background: #444; color: #4ea3ff; font-weight: bold; }
        .sidebar .nav-link:hover:not(.active) { background: #333; color: #4ea3ff; }
        .main-content { margin-left: 200px; width: calc(100vw - 200px); padding: 32px 0 0 32px; overflow-x: visible; background: #111; min-height: calc(100vh - 56px); }
        .ds-searchbar { background: #181818; padding: 24px 24px 16px 24px; border-radius: 16px; margin-bottom: 28px; overflow: visible; }
        .ds-searchbar-inner { background: #111; border-radius: 18px; padding: 10px 20px; display: flex; align-items: center; gap: 12px; border: 2px solid #444; }
        .ds-searchbar-inner input { flex: 1; background: transparent; border: none; outline: none; color: #fff; font-size: 1.15em; font-weight: 500; letter-spacing: 0.01em; padding: 2px 0; }
        .ds-searchbar-inner input::placeholder { color: #aaa; opacity: 1; }
        .ds-searchbar-inner .ds-search-icon { color: #aaa; font-size: 1.3em; }
        #ds-filters { margin-bottom: 32px; }
        .ds-filter-row { display: flex; align-items: center; margin-bottom: 8px; }
        .ds-filter-row .ds-label { color: #f3f3f3; min-width: 72px; font-weight: bold; font-size: 1.05em; flex-shrink: 0; margin-right: 6px; letter-spacing: 0.01em; }
        .ds-filter-options { display: flex; flex-wrap: nowrap; gap: 6px; overflow-x: auto; overflow-y: hidden; white-space: nowrap; scrollbar-width: thin; scrollbar-color: #444 #222; }
        .ds-filter-options::-webkit-scrollbar { height: 6px; background: #222; border-radius: 6px; }
        .ds-filter-options::-webkit-scrollbar-thumb { background: #444; border-radius: 6px; }
        .ds-filter-options::-webkit-scrollbar-thumb:hover { background: #666; }
        .ds-option { color: #ccc; background: none; border: none; outline: none; font-size: 1.04em; padding: 4px 14px; border-radius: 16px; cursor: pointer; transition: background 0.18s, color 0.18s, font-weight 0.18s; font-weight: 400; margin: 0; height: 32px; line-height: 22px; display: inline-block; }
        .ds-option.selected { color: #fff; background: #333; font-weight: 600; }
        .ds-option:disabled { color: #555; cursor: not-allowed; }
        .ds-option:hover:not(:disabled):not(.selected) { background: #222; color: #fff; }
        .ds-card-list { display: flex; gap: 24px; overflow-x: auto; padding-bottom: 12px; }
        .ds-card-list {
            display: flex;
            gap: 24px;
            flex-wrap: wrap;
            align-items: flex-start;
            padding-bottom: 12px;
            overflow-x: unset;
        }
        .ds-card { background: #181818; border-radius: 16px; box-shadow: 0 2px 12px #0006; width: 300px; min-width: 300px; cursor: pointer; transition: transform 0.2s, box-shadow 0.2s; display: flex; flex-direction: column; align-items: center; }
        .ds-card img { width: 100%; height: 400px; object-fit: cover; border-radius: 16px 16px 0 0; background: #222; }
        .ds-card-title { color: #fff; font-size: 1em; padding: 10px 12px 4px 12px; text-align: left; white-space: normal; word-break: break-all; }
        .ds-card:hover, .ds-card:focus { transform: scale(1.06); box-shadow: 0 4px 24px #00f4; outline: 2px solid #fff3; }
        #ds-content .ds-empty { color: #888; text-align: center; padding: 60px 0; }
        #ds-content .ds-loading { color: #aaa; text-align: center; padding: 60px 0; }
        .ds-card-horizontal { width: 400px; min-width: 400px; }
        .ds-card-vertical { width: 300px; min-width: 300px; }
        #tokenDisplay.copied { position: relative; color: #fff !important; background: #28a745 !important; border-color: #28a745 !important; }
        #tokenDisplay.copied #tokenText { opacity: 0.3; }
        #tokenDisplay.copied::after { 
            content: "\2714 Copied!"; 
            position: absolute; 
            top: 0; left: 0; right: 0; bottom: 0; 
            display: flex; align-items: center; justify-content: center; 
            color: #fff; font-size: 1.1em; background: transparent; z-index: 2; 
        }
        .modal-custom-width .modal-dialog {
            max-width: 1020px;
        }
        .modal-custom-width .modal-content {
            background: #f8f9fa;
        }
        /* Custom tooltip for search input */
        .ds-tooltip {
            position: absolute;
            left: 0;
            top: 100%;
            transform: translateY(12px);
            background: #222;
            color: #fff;
            padding: 12px 20px;
            border-radius: 16px;
            box-shadow: 0 4px 16px #0005;
            font-size: 1em;
            z-index: 99999;
            min-width: 260px;
            max-width: 400px;
            white-space: pre-line;
            pointer-events: none;
            opacity: 0;
            transition: opacity 0.18s;
            display: flex;
            align-items: center;
        }
        .ds-searchbar-inner:hover .ds-tooltip,
        .ds-searchbar-inner:focus-within .ds-tooltip {
            opacity: 1;
            pointer-events: auto;
        }
        .ds-tooltip::before {
            content: "";
            position: absolute;
            left: 20px;
            top: -8px;
            border-width: 0 8px 8px 8px;
            border-style: solid;
            border-color: transparent transparent #222 transparent;
        }
    </style>
</head>
<body>
    <!-- Top Bar -->
    <div class="top-bar d-flex align-items-center px-4 justify-content-between">
        <span class="fw-bold" style="font-size:1.1em;">Simulated OS 10 TV For Production Environment</span>
        <div class="d-flex align-items-center">
            <button class="btn btn-success btn-sm me-2" id="tokenDisplay">
                <span id="tokenText">TOKEN_PLACEHOLDER</span>
            </button>
            <button class="btn btn-outline-primary btn-sm me-2" id="deviceInfoBtn">Device Info</button>
            <button class="btn btn-outline-warning btn-sm" id="configBtn">Configuration</button>
        </div>
    </div>
    <!-- 设备信息弹窗 -->
    <div class="modal fade" id="deviceInfoModal" tabindex="-1">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Device Information</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <div id="deviceInfoContent"></div>
                </div>
            </div>
        </div>
    </div>
    <!-- 配置弹窗 -->
    <div class="modal fade" id="configModal" tabindex="-1">
        <div class="modal-dialog modal-lg">
            <div class="modal-content">
                <div class="modal-header">
                    <h5 class="modal-title">Edit Device Configuration</h5>
                    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
                </div>
                <div class="modal-body">
                    <form id="configForm">
                        <div id="configFormFields" class="row g-3"></div>
                    </form>
                </div>
                <div class="modal-footer">
                    <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
                    <button type="button" class="btn btn-outline-danger" id="configResetBtn">Reset</button>
                    <button type="button" class="btn btn-primary" id="configSaveBtn">Save & Reload</button>
                </div>
            </div>
        </div>
    </div>
    <div class="d-flex" style="margin-top:56px;">
        <!-- 侧边栏 -->
        <nav class="sidebar d-flex flex-column p-3">
            <a class="nav-link" href="OS10-home-your-top-choices.html" data-menu="your-top-choice">Your Top Choice</a>
            <a class="nav-link" href="OS10-home.html" data-menu="home">Home</a>
            <a class="nav-link" href="OS10-home-search.html" data-menu="home-search">Home Search</a>
            <a class="nav-link" href="OS10-discovery.html" data-menu="discovery">Discovery</a>
            <a class="nav-link" href="OS10-discovery-search.html" data-menu="discovery-search">Discovery Search</a>
        </nav>
        <!-- 主内容区：Discovery Search -->
        <div class="main-content flex-grow-1">
            <div id="discoverySearchSection">
                <div class="ds-searchbar">
                    <div class="ds-searchbar-inner" style="position:relative;">
                        <span class="ds-search-icon">🔍</span>
                        <input type="text" style="flex:1;background:transparent;border:none;outline:none;color:#fff;font-size:1.2em;" 
                            placeholder="Search not implemented" 
                            disabled>
                        <div class="ds-tooltip">Search function not implemented - The called interface is also Home Search, but the filter conditions are only MOVIE / SEASON / REC_CHANNEL / REC_PROGRAM</div>
                    </div>
                </div>
                <div id="ds-filters">
                    <div class="ds-filter-row" id="ds-type-row"></div>
                    <div class="ds-filter-row" id="ds-genres-row"></div>
                    <div class="ds-filter-row" id="ds-region-row"></div>
                    <div class="ds-filter-row" id="ds-year-row"></div>
                </div>
                <div id="ds-content"></div>
            </div>
        </div>
    </div>
    <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/js/bootstrap.bundle.min.js"></script>
    <script>
    // ========== Top buttons and global variables ==========
    let GLOBAL_PARAMS = JSON.parse(localStorage.getItem('GLOBAL_PARAMS')) || {
        productId: 'wtv10',
        brandId: '7',
        deviceSetId: '10bfa24f235519482a8b9b1c2ad7a3aef6',
        deviceType: 'WHALEOS_ZEASN_962D4_4K_MTP_P4',
        countryCode: 'DE',
        langCode: 'en',
        mac: '18:84:c1:f4:2c:60',
        functionType: 'TvLauncher',
        ifGetTvDetail: '1',
        iconResolution: '320*180',
        terminalType: 'TV',
        sn: '',
        appVersion: '20000043',
        androidVersion: '13',
        osType: 'WhaleOSA',
        clientIp: '217.111.87.254'
    };
    let globalToken = localStorage.getItem('globalToken') || '';
    let lockedClientIp = GLOBAL_PARAMS.clientIp;
    // 真实接口生成token
    async function fetchToken(force = false) {
        if (!force && globalToken) {
            $('#tokenText').text(globalToken);
            return;
        }
        const params = new URLSearchParams({ ...GLOBAL_PARAMS });
        try {
            const response = await $.ajax({
                url: 'https://saas.zeasn.tv/auth-api/api/v1/auth/deviceSign',
                method: 'POST',
                contentType: 'application/x-www-form-urlencoded',
                data: params.toString(),
                processData: false
            });
            if (response.errorCode !== "0") throw new Error('Failed to get token');
            globalToken = response.data.token;
            $('#tokenText').text(globalToken);
            localStorage.setItem('globalToken', globalToken);
        } catch (e) {
            $('#tokenText').text('Failed to generate');
            globalToken = '';
            localStorage.removeItem('globalToken');
        }
    }
    // 页面初始化自动生成token，按钮背景色为白色
    $(async function() {
        $('#tokenDisplay').removeClass('btn-success').addClass('btn-outline-success');
        if (!globalToken) {
            await fetchToken();
        } else {
            $('#tokenText').text(globalToken);
        }
        
        // 检查token是否有效
        if (globalToken) {
            try {
                const res = await $.ajax({
                    url: `https://saas.zeasn.tv/sp/api/device/v1/column?token=${globalToken}`,
                    method: 'GET'
                });
                if (res && res.errorCode === "1000") {
                    $('#discoverySearchSection').html(`
                        <div class='text-danger' style='color:#ff6666;padding:32px 0;text-align:center;'>
                            Token expired (errorCode: 1000)<br>
                            <button id='refreshTokenBtn' class='btn btn-danger btn-sm mt-3'>Regenerate Token</button>
                        </div>
                    `);
                    $('#refreshTokenBtn').off('click').on('click', async function() {
                        $('#refreshTokenBtn').prop('disabled', true).text('Generating...');
                        await fetchToken(true);
                        location.reload();
                    });
                    return;
                }
            } catch (e) {
                // 如果请求失败，继续正常流程
            }
        }
        
        renderDiscoverySearch();
    });
    // 设备信息渲染
    function renderDeviceInfo(data) {
        if (!data) {
            $('#deviceInfoContent').html('<div class="text-center py-4">No device data available</div>');
            return;
        }
        let rows = '';
        // 主体字段
        const mainFields = [
            ['Product ID', data.productId],
            ['App Version', data.appVersion],
            ['Android Version', data.androidVersion],
            ['Brand ID', data.brandId],
            ['Country Code', data.countryCode],
            ['DeviceSet ID', data.deviceSetId],
            ['Device Type', data.deviceType],
            ['MAC', data.mac],
            ['Language', data.langCode],
            ['IP', data.ip],
            ['OS Type', data.osType],
            ['Function Type', data.functionType],
            ['Token', data.token],
        ];
        mainFields.forEach(([k, v]) => {
            rows += `<tr><td>${k}:</td><td>${v ?? ''}</td></tr>`;
        });
        // tvDetailParam 展开
        if (data.tvDetailParam && typeof data.tvDetailParam === 'object') {
            rows += `<tr><td colspan='2'><b>tvDetailParam</b></td></tr>`;
            Object.entries(data.tvDetailParam).forEach(([k, v]) => {
                rows += `<tr><td style='padding-left:2em;'>${k}:</td><td>${v ?? ''}</td></tr>`;
            });
        }
        $('#deviceInfoContent').html(`<table class="device-info-table"><tbody>${rows}</tbody></table>`);
    }
    // Device Info按钮弹窗
    $('#deviceInfoBtn').off('click').on('click', async function() {
        if (!globalToken) {
            alert('Please generate token first');
            return;
        }
        try {
            const res = await $.ajax({
                url: 'https://saas.zeasn.tv/sp/api/device/v1/column/token?token=' + encodeURIComponent(globalToken),
                method: 'GET'
            });
            if (res && res.errorCode === "1000") {
                renderDeviceInfo(null);
                $('#deviceInfoContent').html(`
                    <div class="text-danger text-center py-4">
                        Token expired (errorCode: 1000)<br>
                        <button id="refreshTokenBtn2" class="btn btn-danger btn-sm mt-3">Regenerate Token</button>
                    </div>
                `);
                $('#refreshTokenBtn2').off('click').on('click', async function() {
                    $('#refreshTokenBtn2').prop('disabled', true).text('Generating...');
                    await fetchToken(true);
                    location.reload();
                });
            } else if (res && res.data) {
                renderDeviceInfo(res.data);
            } else {
                renderDeviceInfo(null);
            }
        } catch (e) {
            renderDeviceInfo(null);
            alert('Failed to get device information');
        }
        const modal = new bootstrap.Modal(document.getElementById('deviceInfoModal'));
        modal.show();
    });
    // Token按钮复制
    $(function() {
        $('#tokenDisplay').off('click').on('click', async function() {
            globalToken = $('#tokenText').text();
            if (!globalToken || globalToken === 'Failed to generate' || globalToken === 'Generating...') {
                alert('No available token');
                return;
            }
            try {
                await navigator.clipboard.writeText(globalToken);
                const $btn = $(this);
                $btn.removeClass('btn-outline-success').addClass('btn-success');
                $btn.addClass('copied');
                setTimeout(() => {
                    $btn.removeClass('btn-success').addClass('btn-outline-success');
                    $btn.removeClass('copied');
                }, 1500);
            } catch (err) {
                alert('Copy failed, please select the token manually');
            }
        });
    });
    // 配置弹窗逻辑
    const CONFIG_KEYS = Object.keys(GLOBAL_PARAMS);
    $('#configBtn').click(function() {
        const $fields = $('#configFormFields').empty();
        CONFIG_KEYS.forEach(key => {
            let value = GLOBAL_PARAMS[key];
            $fields.append(`
                <div class="col-12 col-md-6">
                    <label class="form-label fw-bold">${key}</label>
                    <input type="text" class="form-control" name="${key}" value="${value ?? ''}">
                </div>
            `);
        });
        const modal = new bootstrap.Modal(document.getElementById('configModal'));
        modal.show();
    });
    // 配置弹窗保存并生成新token（真实接口）
    $('#configSaveBtn').off('click').on('click', async function() {
        const formArr = $('#configForm').serializeArray();
        formArr.forEach(({name, value}) => {
            GLOBAL_PARAMS[name] = value;
        });
        localStorage.setItem('GLOBAL_PARAMS', JSON.stringify(GLOBAL_PARAMS));
        $('#tokenText').text('Generating...');
        await fetchToken(true); // 强制刷新token
        // 关闭弹窗
        const modal = bootstrap.Modal.getInstance(document.getElementById('configModal'));
        if(modal) modal.hide();
        // 保存后自动刷新页面，确保配置生效
        setTimeout(()=>{ location.reload(); }, 300);
    });
    $('#configResetBtn').click(function() {
        const initial = {
            productId: 'wtv10',
            brandId: '7',
            deviceSetId: '10bfa24f235519482a8b9b1c2ad7a3aef6',
            deviceType: 'WHALEOS_ZEASN_962D4_4K_MTP_P4',
            countryCode: 'DE',
            langCode: 'en',
            mac: '18:84:c1:f4:2c:60',
            functionType: 'TvLauncher',
            ifGetTvDetail: '1',
            iconResolution: '320*180',
            terminalType: 'TV',
            sn: '',
            appVersion: '20000043',
            androidVersion: '13',
            osType: 'WhaleOSA',
            clientIp: '217.111.87.254'
        };
        Object.assign(GLOBAL_PARAMS, initial);
        $('#configForm input').each(function() {
            const key = $(this).attr('name');
            if (key in initial) $(this).val(initial[key]);
        });
        localStorage.removeItem('GLOBAL_PARAMS');
    });
    // ========== Discovery Search Function ==========
    const DS_TYPE_LIST = [
        {label:'Movie', value:'MOVIE'},
        {label:'Season', value:'SEASON'},
        {label:'Channel', value:'CHANNEL'},
        {label:'Program', value:'PROGRAM'}
    ];
    let dsState = {
        type: 'MOVIE',
        genres: '',
        region: '',
        year: '',
        genresList: [],
        regionList: [],
        yearList: [],
        contentList: [],
        loading: false
    };
    let dsInitStatus = { genres: false, regions: false, years: false };
    function resetDsInitStatus() { dsInitStatus = { genres: false, regions: false, years: false }; }
    function tryInitDsContentV2() {
        if(dsInitStatus.genres && dsInitStatus.regions && dsInitStatus.years) {
            fetchDsContent();
        }
    }
    function updateDsFilterVisibility() {
        const hide = ['CHANNEL','PROGRAM'].includes(dsState.type);
        $('#ds-region-row').toggle(!hide);
        $('#ds-year-row').toggle(!hide);
    }
    function renderDsType() {
        const $row = $('#ds-type-row').empty();
        $row.append('<span class="ds-label">Type</span>');
        const $opts = $('<div class="ds-filter-options"></div>');
        DS_TYPE_LIST.forEach(t => {
            $opts.append(`<button class="ds-option${dsState.type===t.value?' selected':''}" data-value="${t.value}">${t.label}</button>`);
        });
        $row.append($opts);
        $opts.find('.ds-option').off('click').on('click', function(){
            const val = $(this).data('value');
            if(dsState.type!==val){
                dsState.type=val; dsState.genres=''; dsState.region='';
                fetchDsGenres();
                fetchDsYears();
                updateDsFilterVisibility();
            }
            // 立即重新渲染，保证选中态
            renderDsType();
            setTimeout(()=>{ this.focus(); }, 0);
        });
        updateDsFilterVisibility();
    }
    function renderDsGenres() {
        const $row = $('#ds-genres-row').empty();
        $row.append('<span class="ds-label">Genres</span>');
        const $opts = $('<div class="ds-filter-options"></div>');
        $opts.append(`<button class="ds-option${dsState.genres===''?' selected':''}" data-value="">All</button>`);
        dsState.genresList.forEach(g => {
            $opts.append(`<button class="ds-option${dsState.genres==g.id?' selected':''}" data-value="${g.id}">${g.name}</button>`);
        });
        $row.append($opts);
        $opts.find('.ds-option').off('click').on('click', function(){
            const val = $(this).data('value');
            if(dsState.genres!==val){
                dsState.genres=val; dsState.region='';
                fetchDsRegions();
            }
            // 立即重新渲染，保证选中态
            renderDsGenres();
            setTimeout(()=>{ this.focus(); }, 0);
        });
    }
    function renderDsRegions() {
        const $row = $('#ds-region-row').empty();
        $row.append('<span class="ds-label">Region</span>');
        const $opts = $('<div class="ds-filter-options"></div>');
        $opts.append(`<button class="ds-option${dsState.region===''?' selected':''}" data-value="">All</button>`);
        dsState.regionList.forEach(r => {
            $opts.append(`<button class="ds-option${dsState.region==r.countryCode?' selected':''}" data-value="${r.countryCode}">${r.name}</button>`);
        });
        $row.append($opts);
        $opts.find('.ds-option').off('click').on('click', function(){
            const val = $(this).data('value');
            if(dsState.region!==val){
                dsState.region=val;
                fetchDsContent();
            }
            renderDsRegions();
            setTimeout(()=>{ this.focus(); }, 0);
        });
    }
    function fetchDsYears() {
        $('#ds-year-row').html('<span class="ds-label">Release Year</span><span style="color:#888;">Loading...</span>');
        $.get(`https://saas.zeasn.tv/whaletime/api/whalemeta/v1/condition/years`, {
            token: globalToken,
            userToken: (typeof GLOBAL_PARAMS === 'object' && GLOBAL_PARAMS.userToken) ? GLOBAL_PARAMS.userToken : '',
            size: 50
        }, function(res){
            if (res && res.errorCode === "1000") {
                $('#ds-year-row').html(`
                    <span class="ds-label">Release Year</span>
                    <div class='text-danger' style='color:#ff6666;padding:8px 0;'>
                        Token expired (errorCode: 1000)<br>
                        <button class='btn btn-danger btn-sm mt-2 refreshTokenBtnYears'>Regenerate Token</button>
                    </div>
                `);
                $('.refreshTokenBtnYears').off('click').on('click', async function() {
                    $(this).prop('disabled', true).text('Generating...');
                    await fetchToken(true);
                    location.reload();
                });
                return;
            }
            dsState.yearList = Array.isArray(res.data)?res.data:[];
            dsState.year = '';
            renderDsYears();
            dsInitStatus.years = true;
            tryInitDsContentV2();
        }).fail(function() {
            $('#ds-year-row').html('<span class="ds-label">Release Year</span><span style="color:#888;">加载失败</span>');
        });
    }
    function renderDsYears() {
        const $row = $('#ds-year-row').empty();
        $row.append('<span class="ds-label">Release Year</span>');
        const $opts = $('<div class="ds-filter-options"></div>');
        $opts.append(`<button class="ds-option${dsState.year===''?' selected':''}" data-value="">All</button>`);
        // 前10年单独展示
        const sortedYears = [...dsState.yearList].sort((a, b) => b - a);
        const years10 = sortedYears.slice(0, 10);
        years10.forEach(y => {
            $opts.append(`<button class="ds-option${dsState.year==y?' selected':''}" data-value="${y}">${y}</button>`);
        });
        // 区间按钮（从第11年开始）
        const remainYears = sortedYears.slice(10);
        if(remainYears.length > 0) {
            const remainSorted = [...remainYears].sort((a, b) => b - a);
            const maxYear = parseInt(remainSorted[0]);
            const minYear = parseInt(remainSorted[remainSorted.length - 1]);
            // 区间1：近6年
            const range1Start = maxYear - 5;
            const range1End = maxYear;
            // 区间2：再往前10年
            const range2Start = Math.max(range1Start - 10, minYear);
            const range2End = range1Start - 1;
            // 区间3：更早
            $opts.append(`<button class="ds-option${dsState.year==`${range1Start}-${range1End}`?' selected':''}" data-value="${range1Start}-${range1End}">${range1Start}-${range1End}</button>`);
            $opts.append(`<button class="ds-option${dsState.year==`${range2Start}-${range2End}`?' selected':''}" data-value="${range2Start}-${range2End}">${range2Start}-${range2End}</button>`);
            if(range2Start > minYear) {
                $opts.append(`<button class="ds-option${dsState.year==`before${range2Start}`?' selected':''}" data-value="before${range2Start}">Before ${range2Start}</button>`);
            }
        }
        $row.append($opts);
        $opts.find('.ds-option').off('click').on('click', function(){
            const val = $(this).data('value');
            if(dsState.year!==val){
                dsState.year=val;
                fetchDsContent();
            }
            // 立即重新渲染，保证选中态
            renderDsYears();
            setTimeout(()=>{ this.focus(); }, 0);
        });
    }
    function renderDsContent() {
        const $c = $('#ds-content').empty();
        // 增加Type选中项Label
        const typeLabel = DS_TYPE_LIST.find(t=>t.value===dsState.type)?.label || '';
        $c.append(`<div class="ds-content-label" style="color:#fff;font-size:1.15em;font-weight:bold;margin-bottom:18px;">${typeLabel}</div>`);
        if(dsState.loading){ $c.append('<div class="ds-loading">Loading...</div>'); return; }
        if(!dsState.contentList.length){
            $c.append('<div class="ds-empty">暂无内容</div>');
            // 保证筛选条件高亮
            renderDsType();
            renderDsGenres();
            renderDsRegions();
            renderDsYears();
            return;
        }
        const $list = $('<div class="ds-card-list"></div>');
        dsState.contentList.forEach(item=>{
            const img = item.cover || item.poster || item.icon || item.image || '';
            const title = item.name || item.title || '';
            // categories 展示
            let categoriesStr = '';
            if (item.moreInfo && Array.isArray(item.moreInfo.categories) && item.moreInfo.categories.length > 0) {
                categoriesStr = `<div style='color:#ffb84d;font-size:0.97em;padding:0 12px 2px 12px;'>${item.moreInfo.categories.map(c => c.name).join(' / ')}</div>`;
            } else if (Array.isArray(item.categories) && item.categories.length > 0) {
                categoriesStr = `<div style='color:#ffb84d;font-size:0.97em;padding:0 12px 2px 12px;'>${item.categories.join(' / ')}</div>`;
            }
            // videoScores 展示
            let videoScoresStr = '';
            if (item.moreInfo && Array.isArray(item.moreInfo.videoScores) && item.moreInfo.videoScores.length > 0) {
                videoScoresStr = `<div style='color:#ffd580;font-size:0.97em;padding:0 12px 2px 12px;'>${item.moreInfo.videoScores.map(vs => `${vs.type||''}: ${vs.value||''}`).join(' / ')}</div>`;
            } else if (Array.isArray(item.videoScores) && item.videoScores.length > 0) {
                videoScoresStr = `<div style='color:#ffd580;font-size:0.97em;padding:0 12px 2px 12px;'>${item.videoScores.map(vs => `${vs.name||''}: ${vs.score||''}`).join(' / ')}</div>`;
            }
            // seasonNumber / episodeCount 展示（仅SEASON类型）
            let seasonNumber = '';
            let episodeCount = '';
            if (item.seasonNumber !== undefined) {
                seasonNumber = item.seasonNumber;
            } else if (item.moreInfo && item.moreInfo.seasonNumber !== undefined) {
                seasonNumber = item.moreInfo.seasonNumber;
            } else if (item.value) {
                try {
                    const v = typeof item.value === 'object' ? item.value : JSON.parse(item.value);
                    if (v.seasonNumber !== undefined) seasonNumber = v.seasonNumber;
                } catch(e){}
            }
            if (item.episodeCount !== undefined) {
                episodeCount = item.episodeCount;
            } else if (item.moreInfo && item.moreInfo.episodeCount !== undefined) {
                episodeCount = item.moreInfo.episodeCount;
            } else if (item.value) {
                try {
                    const v = typeof item.value === 'object' ? item.value : JSON.parse(item.value);
                    if (v.episodeCount !== undefined) episodeCount = v.episodeCount;
                } catch(e){}
            }
            let isSeasonType = (item.objectType === 'SEASON' || dsState.type === 'SEASON' || (item.value && typeof item.value === 'object' && item.value.objectType === 'SEASON'));
            let seasonInfoStr = '';
            if (isSeasonType && (seasonNumber || episodeCount)) {
                let arr = [];
                if (seasonNumber) arr.push('S' + seasonNumber);
                if (episodeCount) arr.push(episodeCount + ' episodes');
                seasonInfoStr = `<div style='color:#ffd580;font-size:0.97em;padding:0 12px 2px 12px;'>${arr.join(' / ')}</div>`;
            }
            // duration 展示（仅MOVIE/VIDEO/PROGRAM类型）
            let duration = '';
            if (item.duration !== undefined) {
                duration = item.duration;
            } else if (item.moreInfo && item.moreInfo.duration !== undefined) {
                duration = item.moreInfo.duration;
            } else if (item.value) {
                try {
                    const v = typeof item.value === 'object' ? item.value : JSON.parse(item.value);
                    if (v.duration !== undefined) duration = v.duration;
                } catch(e){}
            }
            function formatDuration(d) {
                d = Number(d);
                if (isNaN(d) || d <= 0) return '';
                const h = Math.floor(d / 3600);
                const m = Math.floor((d % 3600) / 60);
                const s = d % 60;
                let arr = [];
                if (h > 0) arr.push(h + 'h');
                if (m > 0) arr.push(m + 'm');
                if (s > 0 || arr.length === 0) arr.push(s + 's');
                return arr.join(' ');
            }
            let isMovieType = (
                item.objectType === 'MOVIE' || item.objectType === 'VIDEO' || item.objectType === 'PROGRAM' ||
                dsState.type === 'MOVIE' || dsState.type === 'VIDEO' || dsState.type === 'PROGRAM' ||
                (item.value && typeof item.value === 'object' && (
                    item.value.objectType === 'MOVIE' || item.value.objectType === 'VIDEO' || item.value.objectType === 'PROGRAM'
                ))
            );
            let durationStr = '';
            if (isMovieType && duration) {
                durationStr = `<div style='color:#ffd580;font-size:0.97em;padding:0 12px 2px 12px;'>${formatDuration(duration)}</div>`;
            }
            // 判断卡片横竖
            let cardClass = 'ds-card-vertical';
            let imgStyle = 'width:100%;height:400px;object-fit:cover;border-radius:16px 16px 0 0;background:#222;';
            if(dsState.type === 'CHANNEL' || dsState.type === 'PROGRAM') {
                cardClass = 'ds-card-horizontal';
                imgStyle = 'width:100%;height:225px;object-fit:cover;border-radius:16px 16px 0 0;background:#222;';
            }
            // 发布日期
            let releaseTimeStr = '';
            if (item.releaseTime) {
                const d = new Date(Number(item.releaseTime));
                if (!isNaN(d.getTime())) {
                    const y = d.getFullYear();
                    const m = (d.getMonth()+1).toString().padStart(2,'0');
                    const day = d.getDate().toString().padStart(2,'0');
                    releaseTimeStr = `<div style='color:#6cf;font-size:0.92em;padding:0 12px 2px 12px;'>${y}-${m}-${day}</div>`;
                }
            } else if(item.publishDate || item.releaseDate || item.year) {
                releaseTimeStr = `<div style='color:#6cf;font-size:0.92em;padding:0 12px 2px 12px;'>${item.publishDate||item.releaseDate||item.year}</div>`;
            }
            // value（优先score、rating、value字段）
            let valueStr = '';
            if(item.score !== undefined) valueStr = `<div style='color:#bbb;font-size:0.92em;word-break:break-all;padding:0 12px 2px 12px;'>${item.score}</div>`;
            else if(item.rating !== undefined) valueStr = `<div style='color:#bbb;font-size:0.92em;word-break:break-all;padding:0 12px 2px 12px;'>${item.rating}</div>`;
            else if(item.value !== undefined) valueStr = `<div style='color:#bbb;font-size:0.92em;word-break:break-all;padding:0 12px 2px 12px;'>${item.value}</div>`;
            // 播放源/Deeplink风格
            let sourcesStr = '';
            let deeplinkList = [];
            if(item.moreInfo && Array.isArray(item.moreInfo.deeplinkDetailList) && item.moreInfo.deeplinkDetailList.length > 0) {
                deeplinkList = item.moreInfo.deeplinkDetailList;
            } else if(Array.isArray(item.sources) && item.sources.length > 0) {
                deeplinkList = item.sources;
            }
            if(deeplinkList.length > 0) {
                sourcesStr = `<div style='display:flex;gap:10px;flex-wrap:wrap;padding:0 12px 8px 12px;'>` +
                    deeplinkList.map(link =>
                        `<div style='display:flex;align-items:center;gap:4px;background:#181818;padding:2px 8px 2px 2px;border-radius:6px;'>`+
                        (link.sourceIcon ? `<img src='${link.sourceIcon}' style='width:22px;height:22px;border-radius:4px;'>` : '')+
                        `<span style='color:#fff;font-size:0.97em;'>${link.sourceName||''}</span>`+
                        `<span style='color:#aaa;font-size:0.85em;'>#${link.sourceId||''}</span>`+
                        `</div>`
                    ).join('') + `</div>`;
            } else if(item.sourceName || item.url) {
                sourcesStr = `<div style='display:flex;gap:10px;flex-wrap:wrap;padding:0 12px 8px 12px;'><div style='display:flex;align-items:center;gap:4px;background:#181818;padding:2px 8px 2px 2px;border-radius:6px;'><span style='color:#fff;font-size:0.97em;'>${item.sourceName||item.url}</span></div></div>`;
            }
            $list.append(`<div class="ds-card ${cardClass}" tabindex="0"><img src="${img}" alt="" style="${imgStyle}"><div class="ds-card-title" style="text-align:left;">${title}</div>${categoriesStr}${videoScoresStr}<div style='text-align:left;'>${seasonInfoStr}${durationStr}${releaseTimeStr}${valueStr}${sourcesStr}</div></div>`);
            // 新增：卡片点击跳转详情页
            const $card = $list.children().last();
            $card.off('click').on('click', function() {
                let v = item.value;
                let objectType = '';
                try {
                    if (typeof v === 'string') v = JSON.parse(v);
                } catch(e) {}
                if (v && typeof v === 'object' && v.objectType) objectType = v.objectType;
                
                // 参考 OS10-discovery.html 的处理方式，直接使用原始的 item.value
                const valueParam = encodeURIComponent(typeof item.value === 'string' ? item.value : JSON.stringify(item.value));
                
                if (objectType === 'MOVIE') {
                    window.open(`movie-detail.html?token=${encodeURIComponent(globalToken)}&value=${valueParam}`, '_blank');
                } else if (objectType === 'SEASON') {
                    window.open(`season-detail.html?token=${encodeURIComponent(globalToken)}&value=${valueParam}`, '_blank');
                } else if (objectType === 'VIDEO') {
                    window.open(`video-detail.html?token=${encodeURIComponent(globalToken)}&value=${valueParam}`, '_blank');
                } else if (objectType === 'REC_CHANNEL') {
                    window.open(`channel-detail.html?token=${encodeURIComponent(globalToken)}&value=${valueParam}`, '_blank');
                } else if (objectType === 'REC_PROGRAM') {
                    window.open(`program-detail.html?token=${encodeURIComponent(globalToken)}&value=${valueParam}`, '_blank');
                }
            });
        });
        $c.append($list);
    }
    function getDsObjectType() {
        if(dsState.type === 'CHANNEL') return 'REC_CHANNEL';
        if(dsState.type === 'PROGRAM') return 'REC_PROGRAM';
        return dsState.type;
    }
    function fetchDsGenres() {
        $('#ds-genres-row').html('<span class="ds-label">Genres</span><span style="color:#888;">Loading...</span>');
        $.get(`https://saas.zeasn.tv/whaletime/api/whalemeta/v1/condition/genres`, {
            token: globalToken,
            userToken: (typeof GLOBAL_PARAMS === 'object' && GLOBAL_PARAMS.userToken) ? GLOBAL_PARAMS.userToken : '',
            size: 300,
            langCode: GLOBAL_PARAMS.langCode || 'en',
            objectType: getDsObjectType()
        }, function(res){
            if (res && res.errorCode === "1000") {
                $('#ds-genres-row').html(`
                    <span class="ds-label">Genres</span>
                    <div class='text-danger' style='color:#ff6666;padding:8px 0;'>
                        Token expired (errorCode: 1000)<br>
                        <button class='btn btn-danger btn-sm mt-2 refreshTokenBtnGenres'>Regenerate Token</button>
                    </div>
                `);
                $('.refreshTokenBtnGenres').off('click').on('click', async function() {
                    $(this).prop('disabled', true).text('Generating...');
                    await fetchToken(true);
                    location.reload();
                });
                return;
            }
            dsState.genresList = Array.isArray(res.data)?res.data:[];
            dsState.genres = '';
            renderDsGenres();
            dsInitStatus.genres = true;
            fetchDsRegions();
            tryInitDsContentV2();
        }).fail(function() {
            $('#ds-genres-row').html('<span class="ds-label">Genres</span><span style="color:#888;">加载失败</span>');
        });
    }
    function fetchDsRegions() {
        $('#ds-region-row').html('<span class="ds-label">Region</span><span style="color:#888;">Loading...</span>');
        $.get(`https://saas.zeasn.tv/whaletime/api/whalemeta/v1/condition/countries`, {
            token: globalToken,
            userToken: (typeof GLOBAL_PARAMS === 'object' && GLOBAL_PARAMS.userToken) ? GLOBAL_PARAMS.userToken : '',
            langCode: GLOBAL_PARAMS.langCode || 'en',
            genreId: dsState.genres,
            objectType: getDsObjectType(),
            alphaOrder: true
        }, function(res){
            if (res && res.errorCode === "1000") {
                $('#ds-region-row').html(`
                    <span class="ds-label">Region</span>
                    <div class='text-danger' style='color:#ff6666;padding:8px 0;'>
                        Token expired (errorCode: 1000)<br>
                        <button class='btn btn-danger btn-sm mt-2 refreshTokenBtnRegions'>Regenerate Token</button>
                    </div>
                `);
                $('.refreshTokenBtnRegions').off('click').on('click', async function() {
                    $(this).prop('disabled', true).text('Generating...');
                    await fetchToken(true);
                    location.reload();
                });
                return;
            }
            dsState.regionList = Array.isArray(res.data)?res.data:[];
            dsState.region = '';
            renderDsRegions();
            dsInitStatus.regions = true;
            tryInitDsContentV2();
        }).fail(function() {
            $('#ds-region-row').html('<span class="ds-label">Region</span><span style="color:#888;">加载失败</span>');
        });
    }
    function fetchDsContent() {
        dsState.loading = true;
        renderDsContent();
        const objectType = getDsObjectType();
        // 处理区间筛选和单一年份
        let releaseYearBegin = '';
        let releaseYearEnd = '';
        let releaseYear = '';
        if(/^\d{4}-\d{4}$/.test(dsState.year)) {
            // 区间如 2010-2015
            const [begin, end] = dsState.year.split('-');
            releaseYearBegin = begin;
            releaseYearEnd = end;
        } else if(/^before\d{4}$/.test(dsState.year)) {
            // before区间
            releaseYearBegin = '';
            releaseYearEnd = dsState.year.replace('before', '');
        } else if(dsState.year && !isNaN(Number(dsState.year))) {
            // 单一年份
            releaseYear = dsState.year;
        }
        // 获取选中region的countryCode
        let releaseCountryCode = '';
        if(dsState.region) {
            const regionObj = dsState.regionList.find(r => r.countryCode === dsState.region);
            if(regionObj && regionObj.countryCode) {
                releaseCountryCode = regionObj.countryCode;
            } else {
                releaseCountryCode = dsState.region;
            }
        }
        const params = {
            langCode: GLOBAL_PARAMS.langCode || 'en',
            needPoster: true,
            releaseCountryCode: releaseCountryCode,
            objectType: objectType,
            startIndex: 0,
            size: 30,
            token: globalToken,
            userToken: (typeof GLOBAL_PARAMS === 'object' && GLOBAL_PARAMS.userToken) ? GLOBAL_PARAMS.userToken : '',
            moreInfo: true
        };
        if(releaseYear) {
            params.releaseYear = releaseYear;
        } else {
            params.releaseYearBegin = releaseYearBegin;
            params.releaseYearEnd = releaseYearEnd;
        }
        $.get(`https://saas.zeasn.tv/whaletime/api/whalemeta/v1/retrieve`, params, function(res){
            if (res && res.errorCode === "1000") {
                dsState.loading = false;
                const $c = $('#ds-content').empty();
                const typeLabel = DS_TYPE_LIST.find(t=>t.value===dsState.type)?.label || '';
                $c.append(`<div class="ds-content-label" style="color:#fff;font-size:1.15em;font-weight:bold;margin-bottom:18px;">${typeLabel}</div>`);
                $c.append(`
                    <div class='text-danger' style='color:#ff6666;padding:32px 0;text-align:center;'>
                        Token expired (errorCode: 1000)<br>
                        <button class='btn btn-danger btn-sm mt-3 refreshTokenBtnContent'>Regenerate Token</button>
                    </div>
                `);
                $('.refreshTokenBtnContent').off('click').on('click', async function() {
                    $(this).prop('disabled', true).text('Generating...');
                    await fetchToken(true);
                    location.reload();
                });
                return;
            }
            dsState.contentList = Array.isArray(res.data)?res.data:[];
            dsState.loading = false;
            renderDsContent();
        }).fail(function() {
            dsState.loading = false;
            const $c = $('#ds-content').empty();
            const typeLabel = DS_TYPE_LIST.find(t=>t.value===dsState.type)?.label || '';
            $c.append(`<div class="ds-content-label" style="color:#fff;font-size:1.15em;font-weight:bold;margin-bottom:18px;">${typeLabel}</div>`);
            $c.append('<div class="ds-loading" style="color:#888;">加载失败</div>');
        });
    }
    function renderDiscoverySearch() {
        resetDsInitStatus();
        renderDsType();
        fetchDsGenres();
        fetchDsYears();
    }
    window.renderDiscoverySearch = renderDiscoverySearch;
    // 高亮当前菜单
    $(function() {
        const page = location.pathname.split('/').pop();
        $('.sidebar .nav-link').each(function() {
            const href = $(this).attr('href');
            if (href === page) {
                $(this).addClass('active');
            } else {
                $(this).removeClass('active');
            }
        });
    });
    </script>
</body>
</html> 